#include <iostream>
#include <vector>
#include <set>

#include <time.h>
#include <math.h>

#include "Omega.h"
#include "Variable.h"
#include "Outcome.h"
#include "Preference.h"
#include "PreferenceSet.h"
#include "Constraint.h"

using namespace std;

void scpo(PreferenceSet& P, Omega& O)
{
cout<<"Coucou";
/*	On commence par implémenter l'algorithme qui liste les meilleures solutions
	Il utilise Strong, Ceteris Paribus et Optimist.
*/
	
	vector< vector<int> > result; // Contiendra le résultat
	O.generateIndex(); //On genere l'ensemble des Outcomes sous forme de numero

	int nbC = (int)(P.getAllPreferences()).size();
	vector<Constraint> C; 
	for(int i=0;i<nbC;i++){
		Constraint c(O,P.getPreference(i));
		C.push_back(c);
	} // Les contraintes 


	while(O.getActualSize() != 0)
	{		

		/* 	Premiere etape
			On détecte les outcomes qui ne sont présentes dans aucune partie droite des contraintes
			Et on les ajoute a E
		*/

		vector<int> E;
		// On parcourt toutes les Outcomes de Omega avec un itérateur
		set<int>::iterator lit ((O.getOmega()).begin()), lend((O.getOmega()).end()); 
		for(;lit!=lend;++lit)
		{
			bool ok = true;
			int i(0);
			while( i<(int)C.size() && ok ){
				if( C[i].isInRight( *lit ) ) ok = false;
				i++;
			}
			if( ok && ( i=(int)C.size() ) ){
				// Si on ne l'a croisé dans aucune contrainte (partie droite)
				// Et que l'on a vérifié chaque contrainte
				// On l'ajoute a l'ensemble E
				E.push_back( *lit );
			}
		}


		// Si E est vide, on arrete la fonction
		if((int)E.size() == 0)
		{
			//return result;
		}


		/* 	Deuxième étape
			On Supprime les contraintes qui sont satisfaites :
			- Strong et CP : Ci satisfaite si la partie gauche est vide 
			- Otpimist : Ci satisfaite si une outcome de E appartient a sa partie gauche
			On met a jour Omega et les contraintes restantes
		*/

        for (int j=0;j<E.size();j++)
		{
			// On met Omega à jour
			O.eraseOutcome(E[j]);

            for (int i(nbC-1);i>=0;--i)
            {
				// On supprime les contraintes Optimist satisfaites
                if (C[i].getSemantic() == "Optimist")
                {
                    if (C[i].isInLeft(E[j])) C.erase(C.begin()+i);
                }
				// Et on met à jour les contraintes Strong et CP
				else
				{
					C[i].deleteOutcomeInLeft(E[j]);
					// Il manque a mettre a jour les parties droites selon CP
				}
            }
        }

		// On supprime les contraintes Strong et CP satisfaites
        for (int i(nbC-1);i>=0;--i)
        {
			if (C[i].getSemantic() == "Strong" || C[i].getSemantic() == "CeterisParibus")
            {
				if( C[i].getSizeLeft() == 0 ) C.erase( C.begin() + i ) ;
			}
		}

	
		result.push_back(E);

	}
	//return result;
}

vector< vector<int> > strongMaxSpec(PreferenceSet P, Omega O)
{
	vector< vector<int> > res; // Contiendra le résultat
	
	O.generateIndex();

	int nbPref = (int)(P.getAllPreferences()).size();
	vector<Constraint> C;

	for(int i=0;i<nbPref;i++){
		Constraint c(O,P.getPreference(i));
		C.push_back(c);
	}

	while(O.getActualSize() != 0)
	{		
		vector<int> E;

		set<int>::iterator lit ((O.getOmega()).begin()), lend((O.getOmega()).end()); 
		for(;lit!=lend;++lit)
		{
			bool ok = true;
			for(int i = 0;i<(int)C.size();i++)
			{
				if(C[i].isInLeft(*lit))
				{
					ok = false;

				}			
			}
			if(ok){E.push_back(*lit);}
		}


		if((int)E.size() == 0)
		{
			vector< vector<int> > res2;
			for(int i=(int)res.size()-1;i>=0;i--)
			{
				res2.push_back(res[i]);
			}
			return res2;
		}

		for(int i = 0;i<(int)E.size();i++)
		{
			O.eraseOutcome(E[i]);
		}

		for(int i=0;i<(int)C.size();i++)
		{
			for(int j=0;j<(int)E.size();j++)
			{
				C[i].deleteOutcomeInRight(E[j]);
			}
		}

		for(int i=0;i<(int)C.size();i++)
		{
			if(C[i].getSizeRight() == 0)
			{
				C.erase(C.begin()+i);
			}
		}

		res.push_back(E);
	}
	vector< vector<int> > res2;
	for(int i=(int)res.size()-1;i>=0;i--)
	{
		res2.push_back(res[i]);
	}
	return res2;
}



int main(){
					cout<<"/-------------- TEST V2 ----------------/"<<endl<<endl;



	/* LES VARIABLES */

	Variable v1("M",2,"fish","meat"); v1.show();

	Variable v2("W",2,"white","red"); v2.show();

	Variable v3("D",2,"cake","ice_cream"); v3.show();
	cout<<endl;

	/* OMEGA */

	vector<Variable> vect; 
	vect.push_back(v1); vect.push_back(v2);	vect.push_back(v3); 
	Omega o(vect);

	/* PREFERENCES */

	Preference p1("white","red","fish");
	Preference p2("red","white","meat");
	Preference p3("cake","ice_cream","red");
	p1.setSemantic("Strong"); p2.setSemantic("Strong"); p3.setSemantic("Strong");
	p1.show(); p2.show(); p3.show();

	PreferenceSet ps;
	ps.addPreference(p1);
	ps.addPreference(p2);
	ps.addPreference(p3);

// Test des changements avec l'ancienne fonction strong maximum de spécificité.
// Reste a faire la nouvelle fonction strong/otpimiste/cP

	/*vector< vector<int> > res = strongMaxSpec(ps,o);
	 for(int i = 0;i<(int)res.size();i++)
	{
		cout<<"E["<<i+1<<"] = {"<<endl;
        
		for(int j=0;j<(int)res[i].size();j++)
		{   
			o.generateOutcome(res[i][j]).show();
		}
		cout<<"}"<<endl;
	}*/
cout<<endl<<"Avec CALCUL"<<endl;
	//vector< vector<int> > res2 = 

scpo(ps,o);
	 /*for(int i = 0;i<(int)res2.size();i++)
	{
		cout<<"E["<<i+1<<"] = {"<<endl;
        
		for(int j=0;j<(int)res2[i].size();j++)
		{   
			o.generateOutcome(res2[i][j]).show();
		}
		cout<<"}"<<endl;
	}*/
    
    cout<<endl;





					cout<<endl<<"/-------------- /TEST V2 ----------------/"<<endl;
return 0;
}
